home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / astrolog / src / xgeneral.c < prev    next >
C/C++ Source or Header  |  1995-08-11  |  25KB  |  1,064 lines

  1. /*                                                               -*- C -*-
  2. ** Astrolog (Version 4.40) File: xgeneral.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. /* $VER: $Id: xgeneral.c,v 1.4 1995/07/02 22:22:54 tf Exp $ */
  38.  
  39. #include "astrolog.h"
  40.  
  41.  
  42. #ifdef GRAPH
  43. /*
  44. ******************************************************************************
  45. ** Core Graphic Procedures.
  46. ******************************************************************************
  47. */
  48.  
  49. /* Set the current color to use in drawing on the screen or bitmap array. */
  50.  
  51. void DrawColor(col)
  52. KI col;
  53. {
  54.   if (gi.fFile)
  55.   {
  56. #ifdef PS
  57.     if (gs.fPS) {
  58.       if (gi.kiCur != col)
  59.       {
  60.         PsStrokeForce();      /* Render existing path with current color */
  61.         fprintf(gi.file, "%.2f %.2f %.2f c\n",
  62.           (real)RGBR(rgbbmp[col])/255.0, (real)RGBG(rgbbmp[col])/255.0,
  63.           (real)RGBB(rgbbmp[col])/255.0);
  64.       }
  65.     }
  66. #endif
  67.  
  68. #ifdef META
  69.     if (gs.fMeta)
  70.       gi.kiLineDes = col;
  71. #endif
  72.   }
  73.  
  74. #ifdef X11
  75.   else
  76.     XSetForeground(gi.disp, gi.gc, rgbind[col]);
  77. #endif
  78.  
  79. #ifdef MSG
  80.   else
  81.     _setcolor(col);
  82. #endif
  83.  
  84. #ifdef BGI
  85.   else
  86.     setcolor(col);
  87. #endif
  88.  
  89. #ifdef AMIGA
  90.   else
  91.   {
  92.     /*printf("DrawColor(%d)\n",col);*/
  93.     /*SetAPen(gi.rp, rand()%16);*/
  94.     /*SetAPen(gi.rp, col);*/
  95.     AmigaSetPen(col);
  96.   }
  97. #endif
  98.  
  99.   gi.kiCur = col;
  100. }
  101.  
  102.  
  103. /* Set a single point on the screen. This is the most basic graphic function */
  104. /* and is called by all the more complex routines. Based on what mode we are */
  105. /* in, we either set a cell in the bitmap array or a pixel on the window.    */
  106.  
  107. void DrawPoint(x, y)
  108. int x, y;
  109. {
  110.   if (gi.fFile)
  111.   {
  112.     if (gs.fBitmap)
  113.     {
  114.       /* Force the coordinates to be within the bounds of the bitmap array. */
  115.  
  116.       if (x < 0) x = 0;  else if (x >= gs.xWin) x = gs.xWin-1;
  117.       if (y < 0) y = 0;  else if (y >= gs.yWin) y = gs.yWin-1;
  118.  
  119.       if (gi.yBand)
  120.       {
  121.         y -= gi.yOffset;
  122.         if (y < 0 || y >= gi.yBand)
  123.           return;
  124.       }
  125.       BmSet(gi.bm, x, y, gi.kiCur);
  126.     }
  127.  
  128. #ifdef PS
  129.     else if (gs.fPS)
  130.     {
  131.       DrawColor(gi.kiCur);
  132.       PsLineCap(fTrue);
  133.       fprintf(gi.file, "%d %d d\n", x, y);
  134.       PsStroke(2);
  135.     }
  136. #endif
  137.  
  138. #ifdef META
  139.     else
  140.     {
  141.       gi.kiFillDes = gi.kiCur;
  142.       MetaSelect();
  143.       MetaEllipse(x-gi.nPenWid/2, y-gi.nPenWid/2,
  144.                   x+gi.nPenWid/2, y+gi.nPenWid/2);
  145.     }
  146. #endif
  147.   }
  148.  
  149. #ifdef X11
  150.   else
  151.     XDrawPoint(gi.disp, gi.pmap, gi.gc, x, y);
  152. #endif
  153.  
  154. #ifdef MSG
  155.   else
  156.     _setpixel(gi.xOffset + x, gi.yOffset + y);
  157. #endif
  158.  
  159. #ifdef BGI
  160.   else
  161.     putpixel(gi.xOffset + x, gi.yOffset + y, gi.kiCur);
  162. #endif
  163.  
  164. #ifdef AMIGA
  165.   else
  166.   {
  167. /*
  168.     if (x < 0) x = 0;  else if (x >= gs.xWin) x = gs.xWin-1;
  169.     if (y < 0) y = 0;  else if (y >= gs.yWin) y = gs.yWin-1;
  170. */
  171.     WritePixel( gi.rp, (SHORT)(gi.xOffset + x), (SHORT)(gi.yOffset + y) );
  172.   }
  173. #endif
  174.  
  175. }
  176.  
  177.  
  178. /* Draw dot a little larger than just a single pixel at specified location. */
  179.  
  180. void DrawSpot(x, y)
  181. int x, y;
  182. {
  183. #ifdef PS
  184.   if (gs.fPS)
  185.   {
  186.     PsLineWidth((int)(gi.rLineWid*3.0));
  187.     DrawPoint(x, y);
  188.     PsLineWidth((int)(gi.rLineWid/3.0));
  189.     return;
  190.   }
  191. #endif
  192.  
  193. #ifdef META
  194.   if (gs.fMeta)
  195.   {
  196.     gi.kiFillDes = gi.kiCur;
  197.     MetaSelect();
  198.     MetaEllipse(x-gi.nPenWid, y-gi.nPenWid, x+gi.nPenWid, y+gi.nPenWid);
  199.     return;
  200.   }
  201. #endif
  202.  
  203.   {
  204.     int X,Y;
  205.  
  206. #ifdef AMIGA
  207.     X= x + gi.xOffset;
  208.     Y= y + gi.yOffset;
  209.  
  210. #else
  211.     X= x;
  212.     Y= y;
  213.  
  214. #endif
  215.  
  216.     DrawPoint(X,   Y);
  217.     DrawPoint(X,   Y-1);
  218.     DrawPoint(X-1, Y);
  219.     DrawPoint(X+1, Y);
  220.     DrawPoint(X,   Y+1);
  221.   }
  222. }
  223.  
  224.  
  225. /* Draw a filled in block, defined by the corners of its rectangle. */
  226.  
  227. void DrawBlock(x1, y1, x2, y2)
  228. int x1, y1, x2, y2;
  229. {
  230.   int x, y;
  231.  
  232.   if (gi.fFile) 
  233.   {
  234.     if (gs.fBitmap) 
  235.     {
  236.       if (gi.yBand) {
  237.         y1 -= gi.yOffset;   if (y1 < 0)         y1 = 0;
  238.         y2 -= gi.yOffset;   if (y2 > gi.yBand)  y2 = gi.yBand-1;
  239.       }
  240.  
  241.       for (y = y1; y <= y2; y++)           /* For bitmap, we have to  */
  242.         for (x = x1; x <= x2; x++)         /* just fill in the array. */
  243.           BmSet(gi.bm, x, y, gi.kiCur);
  244.     }
  245.  
  246. #ifdef PS
  247.     else if (gs.fPS)
  248.     {
  249.       DrawColor(gi.kiCur);
  250.       fprintf(gi.file, "%d %d %d %d rf\n",
  251.         Max(x1-gi.nPenWid/4, 0), Max(y1-gi.nPenWid/4, 0),
  252.         x2-x1+gi.nPenWid/4, y2-y1+gi.nPenWid/4);
  253.     }
  254. #endif
  255.  
  256. #ifdef META
  257.     else
  258.     {
  259.       gi.kiFillDes = gi.kiCur;
  260.       MetaSelect();
  261.       MetaRectangle(x1-gi.nPenWid/2, y1-gi.nPenWid/2, x2+gi.nPenWid/2, y2+gi.nPenWid/2);
  262.     }
  263. #endif
  264.   }
  265.  
  266. #ifdef X11
  267.   else
  268.     XFillRectangle(gi.disp, gi.pmap, gi.gc, x1, y1, x2-x1, y2-y1);
  269. #endif
  270.  
  271. #ifdef MSG
  272.   else
  273.     _rectangle(_GFILLINTERIOR, gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
  274. #endif
  275.  
  276. #ifdef BGI
  277.   else {
  278.     setfillstyle(SOLID_FILL, gi.kiCur);
  279.     bar(gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
  280.   }
  281. #endif
  282.  
  283. #ifdef AMIGA
  284.   else
  285.   {
  286.     int x_min, x_max, y_min, y_max;
  287.  
  288.     if(x1<x2) { x_min= x1; x_max= x2; }  else { x_min= x2; x_max= x1; }
  289.     if(y1<y2) { y_min= y1; y_max= y2; }  else { y_min= y2; y_max= y1; }
  290.  
  291.     x_min += gi.xOffset;    y_min += gi.yOffset;
  292.     x_max += gi.xOffset;    y_max += gi.yOffset;
  293.  
  294.     RectFill( gi.rp, x_min,y_min, x_max,y_max );
  295.   }
  296. #endif
  297.  
  298. }
  299.  
  300.  
  301. /* Draw a rectangle on the screen with specified thickness. This is just   */
  302. /* like DrawBlock() except that we are only drawing the edges of the area. */
  303.  
  304. void DrawBox(x1, y1, x2, y2, xsiz, ysiz)
  305. int x1, y1, x2, y2, xsiz, ysiz;
  306. {
  307. #ifdef META
  308.   if (gs.fMeta)
  309.   {
  310.     /* For thin boxes in metafiles, we can just output one rectangle record */
  311.     /* instead of drawing each side separately as we have to do otherwise.  */
  312.     if (xsiz <= 1 && ysiz <= 1)
  313.     {
  314.       gi.kiFillDes = kNull;          /* Specify a hollow fill brush. */
  315.       MetaSelect();
  316.       MetaRectangle(x1, y1, x2, y2);
  317.       return;
  318.     }
  319.   }
  320. #endif /* META */
  321.  
  322.   DrawBlock(x1,            y1,            x2,            y1 + ysiz - 1);
  323.   DrawBlock(x1,            y1 + ysiz,     x1 + xsiz - 1, y2 - ysiz);
  324.   DrawBlock(x2 - xsiz + 1, y1 + ysiz,     x2,            y2 - ysiz);
  325.   DrawBlock(x1,            y2 - ysiz + 1, x2,            y2);
  326. }
  327.  
  328.  
  329. /* Clear and erase the graphics screen or bitmap contents. */
  330.  
  331. void DrawClearScreen()
  332. {
  333. #ifdef PS
  334.   if (gs.fPS)
  335.   {
  336.     /* For PostScript charts first output page orientation information. */
  337.  
  338.     if (!gi.fEps)
  339.     {
  340.       if (gs.nOrient == 0)
  341.         gs.nOrient = (gs.xWin > gs.yWin) ? -1 : 1;
  342.  
  343.       if (gs.nOrient < 0)
  344.       {
  345.         /* chartx and charty are reversed for Landscape mode. */
  346.  
  347.         fprintf(gi.file, "%d %d translate\n",
  348.           ((int)(gs.xInch*72.0+rRound) + gs.yWin)/2,
  349.           ((int)(gs.yInch*72.0+rRound) + gs.xWin)/2);
  350.         fprintf(gi.file, "-90 rotate\n");
  351.       }
  352.  
  353.       else
  354.       {
  355.         /* Most charts are in Portrait mode */
  356.  
  357.         fprintf(gi.file, "%d %d translate\n",
  358.           ((int)(gs.xInch*72.0+rRound) - gs.xWin)/2,
  359.           ((int)(gs.yInch*72.0+rRound) + gs.yWin)/2);
  360.       }
  361.     } else
  362.       fprintf(gi.file, "0 %d translate\n", gs.yWin);
  363.  
  364.     fprintf(gi.file, "1 -1 scale\n");
  365.     gs.nScale *= PSMUL; gs.xWin *= PSMUL; gs.yWin *= PSMUL; gi.nScale *= PSMUL;
  366.     fprintf(gi.file, "1 %d div dup scale\n", PSMUL);
  367.   }
  368. #endif
  369.  
  370. #ifdef META
  371.   if (gs.fMeta)
  372.     MetaInit();    /* For metafiles first go write our header information. */
  373. #endif
  374.  
  375.   /* Don't actually erase the screen if the -Xj switch is in effect. */
  376.  
  377.   if (gs.fJetTrail)
  378.     return;
  379.  
  380. #ifdef MSG
  381.   if (!gi.fFile)
  382.     _clearscreen(_GCLEARSCREEN);
  383. #endif /* MSG */
  384.  
  385. #ifdef BGI
  386.   if (!gi.fFile)
  387.     clearviewport();
  388. #endif
  389.  
  390. #ifdef AMIGA
  391.   if (!gi.fFile)
  392.     AmigaClearScreen();
  393. #endif /* AMIGA */
  394.  
  395.   DrawColor(gi.kiOff);
  396.   DrawBlock(0, 0, gs.xWin - 1, gs.yWin - 1);    /* Clear bitmap screen. */
  397. }
  398.  
  399.  
  400. /* Draw a line on the screen, specified by its endpoints. In addition, we */
  401. /* have specified a skip factor, which allows us to draw dashed lines.    */
  402.  
  403. void DrawDash(x1, y1, x2, y2, skip)
  404. int x1, y1, x2, y2, skip;
  405. {
  406.   int x = x1, y = y1, xadd, yadd, yinc, xabs, yabs, i, j = 0;
  407.  
  408.   if (skip < 0)
  409.     skip = 0;
  410.  
  411. #ifdef ISG
  412.   if (!gi.fFile)
  413.   {
  414.     if (!skip)
  415.     {
  416. #ifdef X11
  417.       /* For non-dashed X window lines, let's have the Xlib do it for us. */
  418.  
  419.       XDrawLine(gi.disp, gi.pmap, gi.gc, x1, y1, x2, y2);
  420. #endif
  421.  
  422. #ifdef PCG
  423.       /* For non-dashed lines, let's have the graphics library do it for us. */
  424.  
  425.       PcMoveTo(gi.xOffset + x1, gi.yOffset + y1);
  426.       PcLineTo(gi.xOffset + x2, gi.yOffset + y2);
  427. #endif
  428.  
  429. #ifdef AMIGA
  430.       {
  431.         UWORD mask= 0;  /* 16 bit dash mask */
  432.         int i,j;
  433.  
  434.         /* taken from the code below... */
  435.  
  436.         for(i= j= 0; i<16; i++)
  437.         {
  438.           if(j<1) mask |= (1<<i);
  439.           j= (j < skip) ? j+1 : 0;
  440.         }
  441.         SetDrPt(gi.rp, mask);
  442.       }
  443.       Move(gi.rp, gi.xOffset+x1,gi.yOffset+y1);
  444.       Draw(gi.rp, gi.xOffset+x2,gi.yOffset+y2);
  445.       SetDrPt(gi.rp, 0xFFFF);
  446. #endif
  447.  
  448.       return;
  449.     }
  450.   }
  451. #endif /* ISG */
  452.  
  453. #ifdef PS
  454.   if (gs.fPS)
  455.   {
  456.     /* For PostScript charts we can save file size if we output a LineTo  */
  457.     /* command when the start vertex is the same as the end vertex of the */
  458.     /* previous line drawn, instead of writing out both vertices.         */
  459.  
  460.     PsLineCap(fTrue);
  461.     PsDash(skip);
  462.  
  463.     if (gi.xPen != x1 || gi.yPen != y1)
  464.       fprintf(gi.file, "%d %d %d %d l\n", x1, y1, x2, y2);
  465.  
  466.     else
  467.       fprintf(gi.file, "%d %d t\n", x2, y2);
  468.  
  469.     gi.xPen = x2; gi.yPen = y2;
  470.     PsStroke(2);
  471.     return;
  472.   }
  473. #endif
  474.  
  475. #ifdef META
  476.   if (gs.fMeta) 
  477.   {
  478.     /* For metafile charts we can really save file size for consecutive */
  479.     /* lines sharing endpoints by consolidating them into a PolyLine.   */
  480.  
  481.     if (gi.xPen != x1 || gi.yPen != y1)
  482.     {
  483.       gi.kiLineDes = (gi.kiLineDes & 15) + 16*(skip > 3 ? 3 : skip);
  484.       MetaSelect();
  485.       gi.pwPoly = gi.pwMetaCur;
  486.       MetaRecord(8, 0x325);      /* Polyline */
  487.       MetaWord(2); MetaWord(x1); MetaWord(y1);
  488.     }
  489.  
  490.     else
  491.     {
  492.       *gi.pwPoly += 2;
  493.       (*(gi.pwPoly+3))++;
  494.       /* Note: We should technically update the max record size in the   */
  495.       /* file header if need be here too, but it doesn't seem necessary. */
  496.     }
  497.  
  498.     MetaWord(x2); MetaWord(y2);
  499.     gi.xPen = x2; gi.yPen = y2;
  500.     return;
  501.   }
  502. #endif
  503.  
  504.   /* If none of the above cases hold, we have to draw the line dot by dot. */
  505.  
  506.   xadd = x2 - x1 >= 0 ? 1 : 3;
  507.   yadd = y2 - y1 >= 0 ? 2 : 4;
  508.  
  509.   xabs = abs(x2 - x1);
  510.   yabs = abs(y2 - y1);
  511.  
  512.   /* Technically what we're doing here is drawing a line which is more    */
  513.   /* horizontal then vertical. We always increment x by 1, and increment  */
  514.   /* y whenever a fractional variable passes a certain amount. For lines  */
  515.   /* that are more vertical than horizontal, we just swap x and y coords. */
  516.  
  517.   if (xabs < yabs)
  518.   {
  519.     SwapN(xadd, yadd);
  520.     SwapN(xabs, yabs);
  521.   }
  522.  
  523.   yinc = (xabs >> 1) - ((xabs & 1 ^ 1) && xadd > 2);
  524.  
  525.   for (i = xabs + 1; i; i--)
  526.   {
  527.     if (j < 1)
  528.       DrawPoint(x, y);
  529.  
  530.     j = j < skip ? j+1 : 0;
  531.  
  532.     switch (xadd) {
  533.     case 1: x++; break;
  534.     case 2: y++; break;
  535.     case 3: x--; break;
  536.     case 4: y--; break;
  537.     }
  538.     yinc += yabs;
  539.  
  540.     if (yinc - xabs >= 0) 
  541.     {
  542.       yinc -= xabs;
  543.       switch (yadd) {
  544.       case 1: x++; break;
  545.       case 2: y++; break;
  546.       case 3: x--; break;
  547.       case 4: y--; break;
  548.       }
  549.     }
  550.   }
  551. }
  552.  
  553.  
  554. /* Draw a normal line on the screen; however, if the x coordinates are close */
  555. /* to either of the two given bounds, then we assume that the line runs off  */
  556. /* one side and reappears on the other, so draw the appropriate two lines    */
  557. /* instead. This is used by the Ley line and astro-graph routines, which     */
  558. /* draw lines running around the world and hence off the edges of the maps.  */
  559.  
  560. void DrawWrap(x1, y1, x2, y2, xmin, xmax)
  561. int x1, y1, x2, y2, xmin, xmax;
  562. {
  563.   int xmid, ymid, i;
  564.  
  565.   if (x1 < 0) {           /* Special case for drawing world map. */
  566.     DrawPoint(x2, y2);
  567.     return;
  568.   }
  569.   xmid = (xmax-xmin) / 2;
  570.  
  571.   /* If endpoints aren't near opposite edges, just draw the line and return. */
  572.  
  573.   if (abs(x2-x1) < xmid) {
  574.     DrawLine(x1, y1, x2, y2);
  575.     return;
  576.   }
  577.   if ((i = (xmax-xmin+1) + (x1 < xmid ? x1-x2 : x2-x1)) == 0)
  578.     i = 1;
  579.  
  580.   /* Determine vertical coordinate where our line runs off edges of screen. */
  581.  
  582.   ymid = y1+(int)((real)(y2-y1)*(x1 < xmid ? (real)(x1-xmin) : (real)(xmax-x1))/(real)i + rRound);
  583.  
  584.   DrawLine(x1, y1, x1 < xmid ? xmin : xmax, ymid);
  585.   DrawLine(x2 < xmid ? xmin : xmax, ymid, x2, y2);
  586. }
  587.  
  588.  
  589. /* This routine, and its companion below, clips a line defined by its  */
  590. /* endpoints to either above some line y=c, or below some line y=c. By */
  591. /* passing in parameters in different orders, we can clip to vertical  */
  592. /* lines, too. These are used by the DrawClip() routine below.         */
  593.  
  594. void ClipLesser(x1, y1, x2, y2, s)
  595. int *x1, *y1, *x2, *y2, s;
  596. {
  597.   *x1 -= (int)((long)(*y1-s)*(*x2-*x1)/(*y2-*y1));
  598.   *y1 = s;
  599. }
  600.  
  601. void ClipGreater(x1, y1, x2, y2, s)
  602. int *x1, *y1, *x2, *y2, s;
  603. {
  604.   *x1 += (int)((long)(s-*y1)*(*x2-*x1)/(*y2-*y1));
  605.   *y1 = s;
  606. }
  607.  
  608.  
  609. /* Draw a line on the screen. This is just like DrawLine() routine earlier; */
  610. /* however, first clip the endpoints to the given viewport before drawing.  */
  611.  
  612. void DrawClip(x1, y1, x2, y2, xl, yl, xh, yh, skip)
  613. int x1, y1, x2, y2, xl, yl, xh, yh, skip;
  614. {
  615.   if (x1 < xl)  ClipLesser (&y1, &x1, &y2, &x2, xl);    /* Check left side of window. */
  616.   if (x2 < xl)  ClipLesser (&y2, &x2, &y1, &x1, xl);
  617.   if (y1 < yl)  ClipLesser (&x1, &y1, &x2, &y2, yl);    /* Check top side of window.  */
  618.   if (y2 < yl)  ClipLesser (&x2, &y2, &x1, &y1, yl);
  619.   if (x1 > xh)  ClipGreater(&y1, &x1, &y2, &x2, xh);    /* Check right of window.  */
  620.   if (x2 > xh)  ClipGreater(&y2, &x2, &y1, &x1, xh);
  621.   if (y1 > yh)  ClipGreater(&x1, &y1, &x2, &y2, yh);    /* Check bottom of window. */
  622.   if (y2 > yh)  ClipGreater(&x2, &y2, &x1, &y1, yh);
  623.  
  624.   DrawDash(x1, y1, x2, y2, skip);                       /* Go draw the line.       */
  625. }
  626.  
  627.  
  628. /* Draw a circle or ellipse inside the given bounding rectangle. */
  629.  
  630. void DrawEllipse(x1, y1, x2, y2)
  631. int x1, y1, x2, y2;
  632. {
  633.   int x, y, rx, ry, m, n, u, v, i;
  634.  
  635.   if (gi.fFile)
  636.   {
  637.     x = (x1+x2)/2; y = (y1+y2)/2; rx = (x2-x1)/2; ry = (y2-y1)/2;
  638.  
  639.     if(gs.fBitmap)
  640.     {
  641.       m = x + rx; n = y;
  642.       for (i = 0; i <= nDegMax; i += DEGINC)
  643.       {
  644.         u = x + (int)(((real)rx+rRound)*RCosD((real)i));
  645.         v = y + (int)(((real)ry+rRound)*RSinD((real)i));
  646.         DrawLine(m, n, u, v);
  647.         m = u; n = v;
  648.       }
  649.     }
  650.  
  651. #ifdef PS
  652.     else if (gs.fPS)
  653.     {
  654.       PsLineCap(fFalse);
  655.       PsStrokeForce();
  656.       PsDash(0);
  657.       fprintf(gi.file, "%d %d %d %d el\n", rx, ry, x, y);
  658.     }
  659. #endif
  660.  
  661. #ifdef META
  662.     else 
  663.     {
  664.       gi.kiFillDes = kNull;    /* Specify a hollow fill brush. */
  665.       MetaSelect();
  666.       MetaEllipse(x1+gi.nPenWid/3, y1+gi.nPenWid/3, x2+gi.nPenWid/3, y2+gi.nPenWid/3);
  667.     }
  668. #endif
  669.   }
  670.  
  671. #ifdef X11
  672.   else
  673.     XDrawArc(gi.disp, gi.pmap, gi.gc, x1, y1, x2-x1, y2-y1, 0, nDegMax*64);
  674. #endif
  675.  
  676. #ifdef MSG
  677.   else
  678.     _ellipse(_GBORDER, gi.xOffset + x1, gi.yOffset + y1, gi.xOffset + x2, gi.yOffset + y2);
  679. #endif
  680.  
  681. #ifdef BGI
  682.   else
  683.     ellipse(gi.xOffset + (x1+x2)/2, gi.yOffset + (y1+y2)/2, 0, 360, (x2-x1)/2, (y2-y1)/2);
  684. #endif
  685.  
  686. #ifdef AMIGA
  687.   else
  688.     AmigaDrawEllipse(gi.rp, gi.xOffset + (x1+x2)/2, gi.yOffset + (y1+y2)/2, (x2-x1)/2, (y2-y1)/2);
  689. #endif
  690.  
  691. }
  692.  
  693.  
  694. /* Print a string of text on the graphic window at specified location. To  */
  695. /* do this we either use Astrolog's own "font" (6x10) and draw each letter */
  696. /* separately, or else specify system fonts for PostScript and metafiles.  */
  697.  
  698. void DrawSz(sz, x, y, dt)
  699. CONST char *sz;
  700. int x, y, dt;
  701. {
  702.   int s = gi.nScale, c = gi.kiCur, cch;
  703.  
  704.   cch = CchSz(sz);
  705.  
  706.   if (!(dt & dtScale))
  707.     gi.nScale = gi.nScaleT;
  708.  
  709.   x += gi.nScale;
  710.  
  711.   if (!(dt & dtLeft))
  712.     x -= cch*xFont*gi.nScale/2;
  713.  
  714.   if (dt & dtBottom)         y -= (yFont-3)*gi.nScale;
  715.   else if (!(dt & dtTop))    y -= yFont*gi.nScale/2;
  716.  
  717.   if (dt & dtErase)
  718.   {
  719.     DrawColor(gi.kiOff);
  720.     DrawBlock(x, y, x+xFont*gi.nScale*cch-1, y+(yFont-2)*gi.nScale);
  721.   }
  722.   DrawColor(c);
  723.  
  724. #ifdef PS
  725.   if (gs.fPS && gs.fFont)
  726.   {
  727.     PsFont(4);
  728.     fprintf(gi.file, "%d %d(%s)center\n", x + xFont*gi.nScale*cch/2, y + yFont*gi.nScale/2, sz);
  729.     gi.nScale = s;
  730.     return;
  731.   }
  732. #endif
  733.  
  734.   while (*sz)
  735.   {
  736.  
  737. #ifdef META
  738.     if (gs.fMeta && gs.fFont)
  739.     {
  740.       gi.nFontDes = 3;
  741.       gi.kiTextDes = gi.kiCur;
  742.       gi.nAlignDes = 0x6 | 0 /* Center | Top */;
  743.       MetaSelect();
  744.       MetaTextOut(x, y, 1);
  745.       MetaWord(WFromBB(*sz, 0));
  746.     } 
  747.     else
  748. #endif
  749.       DrawTurtle(szDrawCh[(_char)*sz-' '], x, y);
  750.  
  751.     x += xFont*gi.nScale;
  752.     sz++;
  753.   }
  754.   gi.nScale = s;
  755. }
  756.  
  757.  
  758. /* Draw the glyph of a sign at particular coordinates on the screen.    */
  759. /* To do this we either use Astrolog's turtle vector representation or  */
  760. /* we may specify a system font character for PostScript and metafiles. */
  761.  
  762. void DrawSign(i, x, y)
  763. int i, x, y;
  764. {
  765. #ifdef PS
  766.   if (gs.fPS && gs.fFont)
  767.   {
  768.     PsFont(1);
  769.     fprintf(gi.file, "%d %d(%c)center\n", x, y, 'A' + i - 1);
  770.     return;
  771.   }
  772. #endif
  773.  
  774. #ifdef META
  775.   if (gs.fMeta && gs.fFont)
  776.   {
  777.     gi.nFontDes = 1;
  778.     gi.kiTextDes = gi.kiCur;
  779.     gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  780.     MetaSelect();
  781.     MetaTextOut(x, y+4*gi.nScale, 1);
  782.     MetaWord(WFromBB('^' + i - 1, 0));
  783.     return;
  784.   }
  785. #endif
  786.  
  787.   DrawTurtle(szDrawSign[i], x, y);
  788. }
  789.  
  790.  
  791. /* Draw the number of a house at particular coordinates on the screen. */
  792. /* We either use a turtle vector or write a number in a system font.   */
  793.  
  794. void DrawHouse(i, x, y)
  795. int i, x, y;
  796. {
  797. #ifdef PS
  798.   if (gs.fPS && gs.fFont)
  799.   {
  800.     PsFont(3);
  801.     fprintf(gi.file, "%d %d(%d)center\n", x, y, i);
  802.     return;
  803.   }
  804. #endif
  805.  
  806. #ifdef META
  807.   if (gs.fMeta && gs.fFont)
  808.   {
  809.     gi.nFontDes = 2;
  810.     gi.kiTextDes = gi.kiCur;
  811.     gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  812.     MetaSelect();
  813.     MetaTextOut(x, y+3*gi.nScale, 1 + (i>9));
  814.     MetaWord(WFromBB(i > 9 ? '1' : '0'+i, i > 9 ? '0'+i-10 : 0));
  815.     return;
  816.   }
  817. #endif
  818.  
  819.   DrawTurtle(szDrawHouse[i], x, y);
  820. }
  821.  
  822.  
  823. /* Draw the glyph of an object at particular coordinates on the screen. */
  824.  
  825. void DrawObject(obj, x, y)
  826. int obj, x, y;
  827. {
  828.   char szGlyph[4];
  829.  
  830.   if (!gs.fLabel)    /* If we are inhibiting labels, then do nothing. */
  831.     return;
  832.  
  833.   /* For other planet centered charts, we have to remember that that     */
  834.   /* particular planet's index now represents the Earth. If we are given */
  835.   /* that index to draw, then change it so we draw the Earth instead.    */
  836.  
  837.   if (gi.nMode != gOrbit && ((obj == us.objCenter && obj > oMoo) || (us.objCenter == 0 && obj == oSun)))
  838.     obj = 0;
  839.  
  840.   DrawColor(kObjB[obj]);
  841.  
  842.   if (obj <= oNorm)
  843.   {
  844.  
  845. #ifdef PS
  846.     if (gs.fPS && gs.fFont == 1 && obj < uranLo && szObjectFont[obj] != ' ')
  847.     {
  848.       PsFont(2);
  849.       fprintf(gi.file, "%d %d(%c)center\n", x, y, szObjectFont[obj]);
  850.       return;
  851.     }
  852. #endif
  853.  
  854. #ifdef META
  855.     if (gs.fMeta && gs.fFont == 1 && obj < uranLo && szObjectFont[obj] != ' ')
  856.     {
  857.       gi.nFontDes = 4;
  858.       gi.kiTextDes = gi.kiCur;
  859.       gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  860.       MetaSelect();
  861.       MetaTextOut(x, y+5*gi.nScale, 1);
  862.       MetaWord(WFromBB(szObjectFont[obj], 0));
  863.       return;
  864.     }
  865. #endif
  866.  
  867.     DrawTurtle(szDrawObject[obj], x, y);
  868.  
  869.   /* Normally we can just go draw the glyph; however, stars don't have */
  870.   /* glyphs, so for these draw their three letter abbreviation.        */
  871.  
  872.   }
  873.   else /* obj > oNorm */
  874.   {
  875.     sprintf(szGlyph, "%c%c%c", chObj3(obj));
  876.     DrawSz(szGlyph, x, y, dtCent);
  877.   }
  878. }
  879.  
  880.  
  881. /* Draw the glyph of an aspect at particular coordinates on the screen. */
  882. /* Again we either use Astrolog's turtle vector or a system Astro font. */
  883.  
  884. void DrawAspect(asp, x, y)
  885. int asp, x, y;
  886. {
  887.   CONST char *sz;
  888.  
  889. #ifdef PS
  890.   if (gs.fPS && gs.fFont == 1 && szAspectFont[asp-1] != ' ')
  891.   {
  892.     PsFont(2);
  893.     fprintf(gi.file, "%d %d(%s%c)center\n", x, y,
  894.       asp == aSSq || asp == aSes ? "\\" : "", szAspectFont[asp-1]);
  895.     return;
  896.   }
  897. #endif
  898.  
  899. #ifdef META
  900.   if (gs.fMeta && gs.fFont == 1 && szAspectFont[asp-1] != ' ')
  901.   {
  902.     gi.nFontDes = 4;
  903.     gi.kiTextDes = gi.kiCur;
  904.     gi.nAlignDes = 0x6 | 0x8 /* Center | Bottom */;
  905.     MetaSelect();
  906.     MetaTextOut(x, y+5*gi.nScale, 1);
  907.     MetaWord(WFromBB(szAspectFont[asp-1], 0));
  908.     return;
  909.   }
  910. #endif
  911.  
  912.   sz = szDrawAspect[asp];
  913.   if (us.fParallel)
  914.   {
  915.     if (asp == aCon)
  916.       sz = "BU4BLD8BR2U8";
  917.     else if (asp = aOpp)
  918.       sz = "BU4BLD8BR2U8BF3BLL6BD2R6";
  919.   }
  920.   DrawTurtle(sz, x, y);
  921. }
  922.  
  923.  
  924. /* Convert a string segment to a positive number, updating the string to  */
  925. /* point beyond the number chars. Return 1 if the string doesn't point to */
  926. /* a numeric value. This is used by the DrawTurtle() routine to extract   */
  927. /* motion vector quantities from draw strings, e.g. the "12" in "U12".    */
  928.  
  929. #if 0
  930. int NFromPch(str)
  931. CONST char **str;
  932. {
  933.   int num = 0, i = 0;
  934.  
  935.   loop
  936.   {
  937.     if (**str < '0' || **str > '9')
  938.       return num > 0 ? num : (i < 1 ? 1 : 0);
  939.  
  940.     num = num*10 + (**str)-'0';
  941.     (*str)++;
  942.     i++;
  943.   }
  944. }
  945. #else  /* slightly improved version by Tobias Ferber, <tf@antares.ping.de> */
  946.  
  947. int NFromPch(str)
  948. CONST char **str;
  949. {
  950.   register int num = 0, i = 0;
  951.   register char *s= (char *)*str;
  952.  
  953.   loop
  954.   {
  955.     if (*s < '0' || *s > '9')
  956.     {
  957.       *str= s;
  958.       return (num > 0) ? num : ((i < 1) ? 1 : 0);
  959.     }
  960.  
  961.     num = num*10 + (*s)-'0';
  962.     ++s;
  963.     ++i;
  964.   }
  965. }
  966. #endif
  967.  
  968. /* This routine is used to draw complicated objects composed of lots of line */
  969. /* segments on the screen, such as all the glyphs and coastline pieces. It   */
  970. /* is passed in a string of commands defining what to draw in relative       */
  971. /* coordinates. This is a copy of the format of the BASIC draw command found */
  972. /* in PC's. For example, "U5R10D5L10" means go up 5 dots, right 10, down 5,  */
  973. /* and left 10 - draw a box twice as wide as it is high.                     */
  974.  
  975. void DrawTurtle(sz, x0, y0)
  976. CONST char *sz;
  977. int x0, y0;
  978. {
  979.   register int i, j, x, y, deltax, deltay;
  980.   bool fBlank, fNoupdate;
  981.   char chCmd;
  982.  
  983.   gi.xTurtle = x0; gi.yTurtle = y0;
  984.  
  985.   while (chCmd = ChCap(*sz))
  986.   {
  987.     sz++;
  988.  
  989.     /* 'B' prefixing a command means just move the cursor, and don't draw. */
  990.  
  991.     if( (fBlank = (chCmd == 'B')) )
  992.     {
  993.       chCmd = ChCap(*sz);
  994.       sz++;
  995.     }
  996.  
  997.     /* 'N' prefixing a command means don't update cursor when done drawing. */
  998.  
  999.     if( (fNoupdate = (chCmd == 'N')) )
  1000.     {
  1001.       chCmd = ChCap(*sz);
  1002.       sz++;
  1003.     }
  1004.  
  1005.     /* Here we process the eight directional commands. */
  1006.  
  1007.     switch (chCmd) {
  1008.     case 'U': deltax =  0; deltay = -1; break;      /* Up    */
  1009.     case 'D': deltax =  0; deltay =  1; break;      /* Down  */
  1010.     case 'L': deltax = -1; deltay =  0; break;      /* Left  */
  1011.     case 'R': deltax =  1; deltay =  0; break;      /* Right */
  1012.     case 'E': deltax =  1; deltay = -1; break;      /* NorthEast */
  1013.     case 'F': deltax =  1; deltay =  1; break;      /* SouthEast */
  1014.     case 'G': deltax = -1; deltay =  1; break;      /* SouthWest */
  1015.     case 'H': deltax = -1; deltay = -1; break;      /* NorthWest */
  1016.     default: PrintError("Bad draw.");       /* Shouldn't happen. */
  1017.     }
  1018.  
  1019.     x = gi.xTurtle;
  1020.     y = gi.yTurtle;
  1021.  
  1022.     j = NFromPch(&sz)*gi.nScale;    /* Figure out how far to draw. */
  1023.  
  1024.     if(fBlank)
  1025.     {
  1026.       gi.xTurtle += deltax*j;
  1027.       gi.yTurtle += deltay*j;
  1028.     }
  1029.  
  1030.     else
  1031.     {
  1032.       if (gs.fPS || gs.fMeta)
  1033.       {
  1034.         gi.xTurtle += deltax*j;
  1035.         gi.yTurtle += deltay*j;
  1036.  
  1037.         DrawLine(x, y, gi.xTurtle, gi.yTurtle);
  1038.       }
  1039.  
  1040.       else
  1041.       {
  1042.         DrawPoint(gi.xTurtle, gi.yTurtle);
  1043.  
  1044.         for (i = 0; i < j; i++)
  1045.         {
  1046.           gi.xTurtle += deltax;
  1047.           gi.yTurtle += deltay;
  1048.  
  1049.           DrawPoint(gi.xTurtle, gi.yTurtle);
  1050.         }
  1051.       }
  1052.  
  1053.       if (fNoupdate)
  1054.       {
  1055.         gi.xTurtle = x;
  1056.         gi.yTurtle = y;
  1057.       }
  1058.     }
  1059.   }
  1060. }
  1061. #endif /* GRAPH */
  1062.  
  1063. /* xgeneral.c */
  1064.